﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Xml.Linq;
using OpenSearch.Client.Util;
using System.Threading.Tasks;

namespace OpenSearch.Client
{
    public class SearchClient : ModelBase
    {
        private readonly SearchProviderInfo _provider;

        private static readonly XNamespace SuggestionNamespace = "http://schemas.microsoft.com/Search/2008/suggestions";
        
        public SearchClient(SearchProviderInfo provider)
        {
            Contract.Requires(provider != null);

            _provider = provider;
        }

        // We must do a couple things here -- based on the search terms, have the Uri ready
        // get the suggestions uri

        private string _searchTerms;

        public string SearchTerms
        {
            get { return _searchTerms; }
            set
            {
                if(value != _searchTerms)
                {
                    
                    _searchTerms = value;

                    OnPropertyChanged(() => SearchTerms);
                    OnPropertyChanged(() => SearchUri);
                    OnPropertyChanged(() => SuggestionsUri);
                }
            }
        }

        public Uri SearchUri
        {
            get
            {
                return OpenSearchUriBuilder.CreateUriFromTerms(_provider.SearchUrl, SearchTerms);
            }
        }

        public Uri SuggestionsUri
        {
            get
            {
                if (_provider.ShowSearchSuggestions)
                {
                    return OpenSearchUriBuilder.CreateUriFromTerms(_provider.SuggestionsUrl, SearchTerms);
                }

                return null;
            }
        }

        public void UpdateTermsFromCurrent(Uri uri)
        {
            var terms = OpenSearchUriBuilder.GetTermsFromUri(_provider.SearchUrl, uri);
            if (terms != null)
            {
                SearchTerms = terms;
            }
        }

        public Uri ImageLocation
        {
            get
            {
                return _provider.FavIconUri;
            }
        }

        public string Name
        {
            get
            {
                return _provider.Name;
            }
        }

        private IEnumerable<SearchSuggestion> _suggestions;

        public IEnumerable<SearchSuggestion> Suggestions
        {
            get { return _suggestions; }
            private set
            {
                _suggestions = value;

                OnPropertyChanged(() => Suggestions);
            }
        }

        public async Task RefreshSuggestions(CancellationToken token)
        {
            if (!_provider.ShowSearchSuggestions)
                return;

            try
            {
                var data = await new WebClient().DownloadStringTaskAsync(SuggestionsUri, token);



                var suggestions = from ele in XDocument.Parse(data).Descendants(SuggestionNamespace + "Item")
                                  select CreateFromElement(ele);

                Suggestions = suggestions.ToList();
            }
            catch (Exception) // ignore the cancel, or any other exception
            {
                Suggestions = Enumerable.Empty<SearchSuggestion>();
            }
        }

        private static SearchSuggestion CreateFromElement(XElement itemElement)
        {
            var imageEle = itemElement.Element(SuggestionNamespace + "Image");
            var textEle = itemElement.Element(SuggestionNamespace + "Text").Value;

            Uri source = null;
            string alt = null;
            int width = 0;
            int height = 0;
                

            if (imageEle != null)
            {
                var sourceAttr = imageEle.Attribute("source");
                var altAttr = imageEle.Attribute("alt");
                var widthAttr = imageEle.Attribute("width");
                var heightAttr = imageEle.Attribute("height");

                if (sourceAttr != null)
                {
                    Uri.TryCreate(sourceAttr.Value, UriKind.Absolute, out source);
                }

                if (altAttr != null)
                {
                    alt = altAttr.Value;
                }

                if (widthAttr != null)
                {
                    int.TryParse(widthAttr.Value, out width);
                }

                if (heightAttr != null)
                {
                    int.TryParse(heightAttr.Value, out height);
                }
            }
            
            return new SearchSuggestion(textEle, source, alt, height, width);
            
        }
    }

    
}
